package com.adopapa.ethexplorer.utils;

import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.ArrayType;
import com.fasterxml.jackson.databind.type.CollectionType;

public class JsonUtil {

	public final static ObjectMapper objectMapper = new ObjectMapper();

	public static String bean2Json(Object obj) throws IOException {
		ObjectMapper mapper = new ObjectMapper();
		StringWriter sw = new StringWriter();
		JsonGenerator gen = new JsonFactory().createGenerator(sw);
		mapper.writeValue(gen, obj);
		gen.close();
		return sw.toString();
	}

	public static <T> T json2Bean(String jsonStr, Class<T> objClass) throws Exception {
		ObjectMapper mapper = new ObjectMapper();
//		mapper.enableDefaultTyping();
		mapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator());
		return mapper.readValue(jsonStr, objClass);
	}

	public static <T> T[] json2Array(String jsonStr, Class<T> objClass) throws Exception {
		ObjectMapper mapper = new ObjectMapper();
//		mapper.enableDefaultTyping();
		mapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator());
		ArrayType arrayType = mapper.getTypeFactory().constructArrayType(objClass);
		T[] results = mapper.readValue(jsonStr, arrayType);
		return results;
	}

	public static <T> List<T> json2List(String jsonStr, Class<T> objClass) throws Exception {
		ObjectMapper mapper = new ObjectMapper();
//		mapper.enableDefaultTyping();
		mapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator());
		CollectionType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, objClass);
		List<T> results = mapper.readValue(jsonStr, listType);
		return results;
	}

	@SuppressWarnings("unchecked")
	public static <T> T getValue(JsonNode jsonObject, String propertyName, Class<T> clazz) {

		JsonNode jsonElement = jsonObject.get(propertyName);
		if (Tools.empty(jsonElement)) {
			return null;
		}
		if (clazz == String.class) {
			String result = jsonElement.asText();
			return Tools.empty(result) ? null : (T) result;
		} else if (clazz == int.class || clazz == Integer.class) {
			return (T) (Integer) jsonElement.asInt();
		} else if (clazz == BigInteger.class) {
			return (T) BigInteger.valueOf(jsonElement.asLong());
		} else if (clazz == float.class || clazz == Float.class //
				|| clazz == double.class || clazz == Double.class) {
			return (T) (Double) jsonElement.asDouble();
		} else if (clazz == long.class || clazz == Long.class) {
			return (T) (Long) jsonElement.asLong();
		} else if (clazz == BigDecimal.class) {
			return (T) BigDecimal.valueOf(jsonElement.asDouble());
		} else if (clazz == boolean.class || clazz == Boolean.class) {
			return (T) (Boolean) jsonElement.asBoolean();
		} else if (clazz == Date.class) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTimeInMillis(jsonElement.asLong());
			return (T) calendar.getTime();
		}

		return null;
	}

}
